from __future__ import annotations

from datetime import datetime, timezone
from typing import Optional

from sqlalchemy import (
    String,
    Integer,
    Float,
    DateTime,
    UniqueConstraint,
)
from sqlalchemy.orm import Mapped, mapped_column

from core.database import Base


class Config(Base):
    __tablename__ = "config"

    key: Mapped[str] = mapped_column(String, primary_key=True)
    value: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    desc: Mapped[Optional[str]] = mapped_column(String, nullable=True)
    create_time: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc))
    update_time: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))


class BacktestResult(Base):
    __tablename__ = "backtest_results"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    strategy_name: Mapped[str] = mapped_column(String, nullable=False)
    strategy_file_path: Mapped[str] = mapped_column(String, nullable=False)
    vt_symbol: Mapped[str] = mapped_column(String, nullable=False)
    interval: Mapped[str] = mapped_column(String, nullable=False)
    start_date: Mapped[str] = mapped_column(String, nullable=False)
    end_date: Mapped[str] = mapped_column(String, nullable=False)
    capital: Mapped[int] = mapped_column(Integer, nullable=False)
    rate: Mapped[float] = mapped_column(Float, nullable=False)
    slippage: Mapped[float] = mapped_column(Float, nullable=False)
    size: Mapped[int] = mapped_column(Integer, nullable=False)
    pricetick: Mapped[float] = mapped_column(Float, nullable=False)

    total_days: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    profit_days: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    loss_days: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    end_balance: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    max_drawdown: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    max_ddpercent: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    max_drawdown_duration: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    total_net_pnl: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    daily_net_pnl: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    total_commission: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    daily_commission: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    total_slippage: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    daily_slippage: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    total_turnover: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    daily_turnover: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    total_trade_count: Mapped[Optional[int]] = mapped_column(Integer, nullable=True)
    daily_trade_count: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    total_return: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    annual_return: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    daily_return: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    win_rate: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    sharpe_ratio: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    ewm_sharpe: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    return_std: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    return_drawdown_ratio: Mapped[Optional[float]] = mapped_column(Float, nullable=True)

    create_time: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc))
    update_time: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))


class ContractInfo(Base):
    __tablename__ = "contract_info"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    vnpy_underlying_symbol: Mapped[str] = mapped_column(String, nullable=False)
    contract_size: Mapped[float] = mapped_column(Float, nullable=False)
    exchange: Mapped[str] = mapped_column(String, nullable=False)
    name: Mapped[str] = mapped_column(String, nullable=False)
    create_time: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc))
    update_time: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))

    __table_args__ = (
        UniqueConstraint("vnpy_underlying_symbol", name="uq_contract_info_symbol"),
    )


class MarginData(Base):
    __tablename__ = "margin_data"

    # Use string date (YYYY-MM-DD) as per existing code
    date: Mapped[str] = mapped_column(String, primary_key=True)
    exchange: Mapped[str] = mapped_column(String, primary_key=True)
    financing_balance: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    financing_buy_amount: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    securities_lending_volume: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    securities_lending_balance: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    securities_lending_sell_volume: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    total_margin_balance: Mapped[Optional[float]] = mapped_column(Float, nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc))
    updated_at: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))



class FuturesAndOptionsDailyPosition(Base):
    __tablename__ = "futures_and_options_daily_position"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    day: Mapped[str] = mapped_column(String, nullable=False)
    symbol_type: Mapped[str] = mapped_column(String, nullable=False)
    symbol: Mapped[str] = mapped_column(String, nullable=False)
    amount: Mapped[float] = mapped_column(Float, nullable=False)
    cost: Mapped[float] = mapped_column(Float, nullable=False)
    pnl: Mapped[float] = mapped_column(Float, default=0)
    create_time: Mapped[int] = mapped_column(Integer, default=lambda: int(datetime.now(timezone.utc).timestamp()))
    update_time: Mapped[int] = mapped_column(Integer, default=lambda: int(datetime.now(timezone.utc).timestamp()), onupdate=lambda: int(datetime.now(timezone.utc).timestamp()))

    __table_args__ = (
        UniqueConstraint("day", "symbol_type", "symbol", name="uq_futures_and_options_daily_position"),
    )


class FuturesAndOptionsTrade(Base):
    __tablename__ = "futures_and_options_trade"

    id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
    day: Mapped[str] = mapped_column(String, nullable=False)
    symbol_type: Mapped[str] = mapped_column(String, nullable=False)
    symbol: Mapped[str] = mapped_column(String, nullable=False)
    amount: Mapped[float] = mapped_column(Float, nullable=False)
    cost: Mapped[float] = mapped_column(Float, nullable=False)
    trade_time: Mapped[datetime] = mapped_column(DateTime, nullable=False)
    create_time: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc))
    update_time: Mapped[datetime] = mapped_column(DateTime, default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc))

    __table_args__ = (
        UniqueConstraint("day", "symbol_type", "symbol", "trade_time", name="uq_futures_and_options_trade"),
    )
